const fs = require('fs');
const path = require('path');
const hx = require('hbuilderx');
const MPServerless = require('@alicloud/mpserverless-node-sdk').default;
const tcb = require("@cloudbase/node-sdk");

let Html = fs.readFileSync(path.join(path.resolve(__dirname),'viewer','dist','index.html'),'utf8');
const staticPath = path.join(path.resolve(__dirname),'viewer','dist', 'index.js');
Html=Html.replace('index.js',staticPath)

const token_cache={};
const tasks={};
const webviews={};
const getFunctionList=function(param){
	const provider=getProvider(param);
	let dir=path.join(param.workspaceFolder
			.uri.fsPath,
		`uniCloud-${provider}`,'cloudfunctions');
		let functions = []
		const files = fs.readdirSync(dir)
		files.forEach(function (item, index) {
		    let stat = fs.lstatSync(path.join(dir,item))
		    if (stat.isDirectory() === true
				&& item!=='common'
				&& item!=='action') { 
		      functions.push({
				  name:item,
				  params:{},
				  checked:false,
			  })
		    }
		})
	return functions
}

const getProvider=function(param){
	if(param.fsPath.indexOf('uniCloud-aliyun')>-1){
		return 'aliyun'
	}
	if(param.fsPath.indexOf('uniCloud-tcb')>-1){
		return 'tcb'
	}
	throw new Error('provider 错误')
}

const spaceId_cache={};
const getSpaceId=async function(param){
	let result;
	let id=param.workspaceFolder.id;
	if(spaceId_cache[id]){
		return spaceId_cache[id];
	}
	try {
		result = await hx.unicloud.getExistsUnicloudAndBindSpace({
			workspaceFolder: param.workspaceFolder
		});
		if(result && result.spaceId){
			spaceId_cache[id]=result.spaceId;
		}
		return result && result.spaceId
	} catch (e) {
		console.error(e)
		return "error"
	}
}

const getSpaceClient=async function(appid,provider,spaceId){
	let cache=token_cache[spaceId];
	let now=Date.now();
	if(cache && cache.client && cache.expire>now+10000){
		return cache.client;
	}
	console.log('获取client',appid,provider,spaceId)
	const res=await hx.http.request({
		url: "https://ide.liuyingyong.cn/serverless/space/debug-token",
		method: "post",
		params: {
			param: JSON.stringify({
				header: {
					token: "${user.checked.token}"
				},
				body: {
					provider: provider,
					spaceId: spaceId,
					appid: appid
				}
			})
			}
	})
	console.log('获取client耗时',now-Date.now(),appid,provider,spaceId)
	let data=JSON.parse(res.data).body
	let client;
	if(provider==='aliyun'){
		const {
			Token:serverSecret
		} = data.Credentials;
		client = new MPServerless({
		    spaceId:spaceId,
		    serverSecret:serverSecret,
			endpoint:'https://api.bspapp.com'
		});
	}else{
		const {
			TmpSecretId:secretId,
			TmpSecretKey: secretKey,
			Token: sessionToken
		} = data.Credentials;
		client = tcb.init({
		  secretId: secretId,
		  secretKey: secretKey,
		  serverSecret: sessionToken,
		  sessionToken: sessionToken,
		  spaceId: spaceId,
		  env:spaceId,
		  "context": {
				"SOURCE": "functiontester",
				"CLIENTIP": "127.0.0.1",
				"CLIENTUA": "functiontester",
				"SPACEINFO": {
				  "spaceId": spaceId,
				  "provider": "tencent"
				},
			}
		});
	}
	const restTime = parseInt(data.RestTime);
	token_cache[spaceId] = {
		client,
		expire: now + 1000 * restTime
	}
	client.invokeFunction=async function(spaceId,name,params){
		let options=tasks[spaceId]
		if(!options || options.task.status===0){
			return;
		}
		const startTime=Date.now()
		try{
			if(client.function){
				let res = await client.function.invoke(name,params);
				return {
					name,
					spendTime:Date.now()-startTime
				};
			}else if(client.callFunction){
				let res = await client.callFunction({
					name,
					data:params
				});
				return {
					name,
					spendTime:Date.now()-startTime
				};
			}else{
				throw new Error('invoke未实现')
			}
		}catch(e){
			return {
				name,
				error:e.message,
				spendTime:Date.now()-startTime
			};
		}
	}
	return client;
}

const saveTaskConfig=(spaceId,options)=>{
	let config=JSON.parse(JSON.stringify(options));
	delete config.task.status
	delete config.task.results
	const filepath=path.join(path.resolve(__dirname),spaceId+'.json');
	console.log('保存配置文件到',filepath)
	fs.writeFileSync(filepath,JSON.stringify(config),'utf8')
}
const loadTaskConfig=(spaceId,param)=>{
	const functions=getFunctionList(param);
	let config=tasks[spaceId];
	const filepath=path.join(path.resolve(__dirname),spaceId+'.json');
	let options={
		functions:functions,
		task:{
			globalParams:{},
			iterations:1000,
			delay:1000,
			status:0,
			results:[],
		},
	};
	if(!config && fs.existsSync(filepath)){
		console.log('加载云空间配置文件',filepath)
		config=fs.readFileSync(filepath,'utf8')
		config=JSON.parse(config);
		config.task.status=0;
		config.task.results=[];
	}
	if(config){
		if(config.functions){
			const functions_map={};
			config.functions.forEach((func)=>{
				functions_map[func.name]=func;
			})
			options.functions.forEach((func,index)=>{
				if(functions_map[func.name]){
					options.functions[index]=functions_map[func.name]
				}
			})
		}
		if(config.task){
			options.task=Object.
							assign(options.task,config.task)
		}
	}
	return options;
}
const runTasks=async function(appid,provider,spaceId,options){
	const client =await getSpaceClient(appid,provider,spaceId);
	let total=0;
	let finishTotal=0;
	let intervalId;
	options.task.status=1;
	options.task.results=[];
	tasks[spaceId]=options;
	saveTaskConfig(spaceId,options);
	let checkFinish=(resolve)=>{
		finishTotal++;
		if(finishTotal>=options.task.iterations
			||options.task.status===0){
			console.log('任务完成')
			options.task.status=0;
			resolve();
		}
	}
	
	const doTask=(resolve)=>{
		if(total>=options.task.iterations 
			|| options.task.status===0){
			checkFinish(resolve);
			return;
		}
		total++;
		let promises=[];
		(options.functions||[]).forEach((func)=>{
			if(func.checked){
				let params = Object.assign(options.task.globalParams,func.params)
				promises.push(client.invokeFunction(spaceId,func.name, params))
			}
		})
		Promise.all(promises).then((results) => {
			if(options.task.status===1){
				results.forEach((item)=>{
					if(item&&item.name){
						options.task.results.push(item)
					}
					
				})
				if(webviews[spaceId]){
					webviews[spaceId].postMessage({
						command:'frame',
						data:results
					})
				}
			}
			checkFinish(resolve);
		}).catch((error) => {
			checkFinish(resolve);
		})
		if(options.task.delay<100 && !webviews[spaceId]){
			setTimeout(()=>{
				doTask(resolve)
			},100)
		}else{
			setTimeout(()=>{
				doTask(resolve)
			},options.task.delay)
		}
	}
	return new Promise((resolve,reject)=>{
		doTask(resolve)
	});
}

const showView=async (param)=> {
	const start=Date.now();
	console.log('开始启动')
	let spaceId=await getSpaceId(param);
	if(!spaceId){
		return hx.window.showErrorMessage('当前项目没有绑定服务空间')
	}
	if(spaceId==='error'){
		return hx.window.showErrorMessage('云函数压测-初始化失败,请重试！')
	}
	console.log('步骤1耗时',Date.now()-start)
	const provider=getProvider(param);
	const appid=param.workspaceFolder.appid;
	let options=loadTaskConfig(spaceId,param);
	console.log('步骤2耗时',Date.now()-start)
	let webviewDialog = hx.window.createWebViewDialog({
		modal: true,
		title: "云函数-压力测试:spaceId="+spaceId,
		description: "",
		size: {
			width: 1360,
			height: 815
		}
	}, {
		enableScripts: true
	});
	let webview = webviewDialog.webView;
	webview.html = Html.replace('===initConfig===',JSON.stringify(options));
	console.log('步骤3耗时',Date.now()-start)
	webview.onDidReceiveMessage(async (msg) => {
		let action = msg.command;
		switch (action) {
			case 'runTask':
				if(__dirname.indexOf('plugins')>-1){
					hx.window.showErrorMessage('该插件不支持正式环境下运行请clone源码后以调试模式运行')
					return;
				}
				setTimeout(async ()=>{
					let options = msg.data;
					await runTasks(appid,provider,spaceId,options)
					if(webviews[spaceId]){
						webviews[spaceId].postMessage({
							command:'finish'
						})
					}
					hx.window.showErrorMessage('压测任务完成')
				},100)
				break;
			case 'stopTask':
				let task=tasks[spaceId]||{};
				task.task.status=0;
				break;
			default:
				break;
		};
	});
	webviewDialog.onDialogClosed(()=>{
		webviews[spaceId]=null;
	})
	let promi = webviewDialog.show();
	console.log('步骤4耗时',Date.now()-start)
	promi.then(function(data) {
		if(data.code===0){
			webviews[spaceId]=webview;
		}
		console.log('启动耗时',Date.now()-start)
	});
};

module.exports = showView;